#include "CXScheduler.h"
#include "io/SerializeBasic.h"
#include "io/FileOp.h"


std::mutex logMutex;

LOGGER logger("task_log.csv");
CXScheduler sch;


CXScheduler::CXScheduler() {}

void CXScheduler::OpenDB(const std::string &d)
{
    int rc;
    // 打开数据库文件，如果文件不存在，则创建它
    rc = sqlite3_open(d.c_str(), &db);
    if (rc) {
        std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << std::endl;
    } else {
        std::cout << "数据库成功打开!" << d << std::endl;
    }
}

void CXScheduler::CloseDB()
{
    std::cout << "数据库关闭!" << std::endl;
    sqlite3_close(db);
}

// 回调函数结构体，用于接收查询结果
struct QueryResult {
    int chain_value;
};

static int callback(void* data, int argc, std::string argv) {
    QueryResult* result = static_cast<QueryResult*>(data);
    if (argc > 0 && argv[0]) {
        result->chain_value = stoi(argv);
    }
    return 0;
}

int CXScheduler::GetChainByID(int wrlID, int partID)
{
    sqlite3_stmt* stmt;
    QueryResult result;
    char* zErrMsg = 0;
    const char* query_sql = "SELECT CHAIN FROM Chains WHERE WRLID =? AND PARTID =?";
    int rc;

    rc = sqlite3_prepare_v2(db, query_sql, -1, &stmt, 0);
    if (rc == SQLITE_OK) {
        sqlite3_bind_int(stmt, 1, wrlID);
        sqlite3_bind_int(stmt, 2, partID);

        // 执行查询并调用回调函数处理结果
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_ROW) {
            std::string xx = reinterpret_cast<const char*>(sqlite3_column_text(stmt,0));
            callback(&result, sqlite3_column_count(stmt), xx);
            // result.chain_value = sqlite3_column_text(stmt,0);
        }
        sqlite3_finalize(stmt);

    } else {
        std::cerr << "SQL error: " << zErrMsg << std::endl;
        sqlite3_free(zErrMsg);
        return -2;
    }

    int UDD = result.chain_value;
    return UDD;
}

int CXScheduler::GetChainByStation(int stID, TaskType tp,int chain_ori)
{
    if(-2 == chain_ori){
        return chain_ori;   /** 筋板不修改 **/
    }
    if(tp == TASK_WELD_BASE_SCAN || tp == TASK_WELD_POINT1 || tp == TASK_WELD_POINT2 || tp == TASK_WELD_FULL)
    {
        if(1 == stID){
            return ch1Real;
        }else{
            return ch2Real;
        }

    }else if(tp == TASK_ASSEMBLE_PART1 || tp == TASK_ASSEMBLE_PART2){
        return chAssReal;
    }else if(tp == TASK_LOAD_UP){
        return chUp;
    }else if(tp == TASK_LOAD_DOWN){
        return chDown;
    }else{
        return chain_ori;
    }
}


Scheduler::Scheduler(const std::vector<OneWrlInfo>& sts) : wrls(sts) {

}

Scheduler::~Scheduler() {

}

// 创建所有任务
TimeUnit Scheduler::GetWRLAss(const std::string &name)
{
    for(auto w:wrls)
    {
        if(w.name == name){
            return w.assTime;
        }
    }

    return 0;
}

void Scheduler::createAllTasks() {
    for(int i =0;i<sch.moniCount;i++){
        if(!wrls.empty()){
            wrls.emplace_back(wrls.front());
            wrls.emplace_back(wrls.at(1));
        }
    }
    for (auto& station : wrls) {
        // 1. 底板上料
            tasks.emplace_back(TASK_LOAD_UP, station.name, station.workpieceModel,
                           station.LoaderTime,station.j_up,  station.wrlid, 0 ,station.j_up_link,station.j_up_DB);

            // 2. 焊接机器人底板扫描
            tasks.emplace_back(TASK_WELD_BASE_SCAN, station.name, station.workpieceModel,
                               station.BGSTime,station.j_scan,  station.wrlid,0,"",station.j_scan_DB);

            TimeUnit timeALL = 0;
            // 3. 装配零件和点焊
            for (int p = 0; p < station.totalParts; ++p) {
                // 装配第一阶段
                tasks.emplace_back(TASK_ASSEMBLE_PART1, station.name, station.workpieceModel,
                                   station.parts[p].partAssTimes1,station.parts[p].js_Ass1,
                                   station.wrlid, p+1,station.parts[p].js_part1);
                // 点焊第一阶段
                tasks.emplace_back(TASK_WELD_POINT1, station.name, station.workpieceModel,
                                   station.parts[p].partTimes1,station.parts[p].js_t1, station.wrlid, p+1);
                // 装配第2阶段
                tasks.emplace_back(TASK_ASSEMBLE_PART2, station.name, station.workpieceModel,
                                   station.parts[p].partAssTimes2,station.parts[p].js_Ass2, station.wrlid, p+1,station.parts[p].js_part2);
                // 装配第2阶段
                tasks.emplace_back(TASK_WELD_POINT2, station.name, station.workpieceModel,
                                   station.parts[p].partTimes2,station.parts[p].js_t2, station.wrlid, p+1);

                timeALL += station.parts[p].partAssTimes1;
                timeALL += station.parts[p].partTimes1;
                timeALL += station.parts[p].partAssTimes2;
                timeALL += station.parts[p].partTimes2;
            }

            station.assTime = timeALL;

            // 4. 满焊
            tasks.emplace_back(TASK_WELD_FULL, station.name, station.workpieceModel,
                               station.fullWeldTime,station.j_full, station.wrlid,0,"",station.j_full_DB);

            // 5. 下料
            tasks.emplace_back(TASK_LOAD_DOWN, station.name, station.workpieceModel,
                               station.unLoaderTime,station.j_down,  station.wrlid, 0 ,station.j_down_link,station.j_down_DB);

            tasks.back().link_part_json = station.j_down_link_part;
        }
}

// 调度所有任务
void Scheduler::scheduleAllTasks() {

    unloader.unloaderTimes["SA"] = -1;
    unloader.unloaderTimes["SB"] = -1;


    for (auto& task : tasks) {
        switch (task.type) {
        case TASK_LOAD_UP:
            scheduleLoadUp(task);
            break;
        case TASK_WELD_BASE_SCAN:
            scheduleWeldBaseScan(task);
            break;
            case TASK_ASSEMBLE_PART1:
                scheduleAssemblyPhase1(task);
                break;
            case TASK_WELD_POINT1:
                scheduleSpotWeldPhase1(task);
                break;
            case TASK_ASSEMBLE_PART2:
                scheduleAssemblyPhase2(task);
                break;
            case TASK_WELD_POINT2:
                scheduleSpotWeldPhase2(task);
                break;
            case TASK_WELD_FULL:
                scheduleWeldFull(task);
                break;
            case TASK_LOAD_DOWN:
                scheduleLoadDown(task);
                break;
            default:
                break;
            }
        }
}

std::string GetFriendSta(const std::string &a)
{
    if("SA"  == a){
        return "SB";
    }else{
        return "SA";
    }
}



void Scheduler::scheduleLoadUp(const Task& task) {
    // 确定任务开始时间
        size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
        OneWrlInfo& wrlInfo = wrls[stationIndex];

        TimeUnit start_time = 0;

        if(unloader.unloaderTimes[task.station] < 0){
            start_time = loader.available_time;
        }else{
            if(unloader.unloaderStates[task.station]){
                start_time = unloader.unloaderTimes[task.station];
            }else{
                std::cerr << "当前工位工件未下料"<<std::endl;
            }
        }

        auto end_time = start_time + task.duration;
        logger.logTask(task, start_time, end_time);
        logger.logTaskNoThisJoint(task, start_time, end_time,task.link_json);

        // 更新加载机器人的可用时间
        loader.available_time = end_time;
        wrlInfo.nextAvailableTime = end_time;
        wrlInfo.isWorking = true;

        unloader.unloaderStates[task.station] = false;
}

// 调度焊接机器人底板扫描任务
void Scheduler::scheduleWeldBaseScan(const Task& task) {
    // 找到对应工位的焊接机器人
        size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);

        OneWrlInfo& wrlInfo = wrls[stationIndex];

        // 确定底板扫描任务的开始时间
        auto start_time = wrlInfo.nextAvailableTime; // 使用下一个可用时间作为开始时间
        auto end_time = start_time + task.duration;

        logger.logTask(task, start_time, end_time);

        // 更新底板扫描任务的完成时间
        wrlInfo.baseScanCompletionTime = end_time;
        wrlInfo.baseScanCompleted = true; // 标记底板扫描任务完成

        // 更新焊接机器人的可用时间
        wrlInfo.nextAvailableTime = end_time;
}



// 检查工位的底板扫描是否完成
bool Scheduler::isBaseScanCompleted(const std::string& wrlName) {
    size_t stationIndex = getOneWrlInfoIndex(wrlName);
    // 返回该工位的底板扫描完成状态
    return wrls[stationIndex].baseScanCompleted;
}

// 调度装配零件任务
void Scheduler::scheduleAssemblyPhase1(const Task& task) {
    // 获取任务对应的工位
    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    OneWrlInfo& wrlInfo = wrls[stationIndex];

    // 确保底板扫描任务已完成
    if (!wrlInfo.baseScanCompleted) {
        std::cerr << "Error: Base scan not completed before assembly phase 1." << std::endl;
        return;
    }

    auto fr = GetFriendSta(task.station);

    auto tms = GetWRLAss(task.workpieceModel);

    auto s1 = wrlInfo.nextAvailableTime + tms;
    auto s2 = assembler.sTime[fr];
    auto s3 = assembler.eTime[fr];

    TimeUnit start_time = 0;
    if(s1 < s2 && s1 < s3 && task.partID == 1){
        start_time = wrlInfo.nextAvailableTime;
    }else{
        // 装配 1 阶段
        start_time = std::max(wrlInfo.baseScanCompletionTime,wrlInfo.nextAvailableTime);
        if(s1 < s2 && s1 < s3){

        }else{
            start_time = std::max(start_time,assembler.vTime[fr]);

        }

    }


    auto end_time = start_time + task.duration; // 假设装配阶段 1 时长为 20 秒
    logger.logTask(task, start_time, end_time);
    logger.logTaskNoThisJoint(task, start_time, end_time,task.link_json);

    // 更新装配机器人的可用时间
    wrlInfo.nextAvailableTime = end_time;


    if(task.partID == 1){
        assembler.sTime[task.station] = start_time;
    }
    assembler.eTime[task.station] = end_time;
}

// 调度点焊阶段 1
void Scheduler::scheduleSpotWeldPhase1(const Task& task) {
    // 获取任务对应的工位
    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    OneWrlInfo& wrlInfo = wrls[stationIndex];

    // 确保装配阶段 1 已完成
    auto start_time = wrlInfo.nextAvailableTime; // 点焊 1 阶段紧接着装配阶段 1 完成
    auto end_time = start_time + task.duration; // 假设点焊阶段 1 时长为 20 秒
    logger.logTask(task, start_time, end_time);
    // 更新焊接机器人的可用时间
    wrlInfo.nextAvailableTime = end_time;
}

// 调度拼装阶段 2
void Scheduler::scheduleAssemblyPhase2(const Task& task) {
    // 获取任务对应的工位
    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    OneWrlInfo& wrlInfo = wrls[stationIndex];

    // 拼装 2 阶段，独立于点焊阶段
    auto start_time = wrlInfo.nextAvailableTime;
    auto end_time = start_time + task.duration;
    logger.logTask(task, start_time, end_time);
    logger.logTaskNoThisJoint(task, start_time, end_time,task.link_json);

    // 更新装配机器人的可用时间
    // wrlInfo.nextAvailableTime = end_time;
}

// 调度点焊阶段 2
void Scheduler::scheduleSpotWeldPhase2(const Task& task) {
    // 获取任务对应的工位
    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    OneWrlInfo& wrlInfo = wrls[stationIndex];

    // 点焊 2 阶段，独立于装配阶段 2
    auto start_time = wrlInfo.nextAvailableTime; // 点焊阶段 2 紧接着点焊阶段 1 完成
    auto end_time = start_time + task.duration; // 假设点焊阶段 2 时长为 20 秒
    logger.logTask(task, start_time, end_time);

    // 更新焊接机器人的可用时间
    wrlInfo.nextAvailableTime = end_time;
}


// 调度满焊任务
void Scheduler::scheduleWeldFull(const Task& task) {
    // 找到对应工位的焊接机器人
    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    WeldRobot& weldRobot = weldRobots[task.station];

    // 确定任务开始时间
    auto &wrlInfo = wrls[stationIndex];
    // 满焊任务应在所有点焊任务完成后开始
    // auto start_time = std::max(wrlInfo.nextAvailableTime,weldRobot.available_time);
    auto start_time = wrlInfo.nextAvailableTime;
    auto end_time = start_time + task.duration;

    logger.logTask(task, start_time, end_time);

    // 更新焊接机器人的可用时间
    weldRobot.available_time = end_time;
    wrlInfo.nextAvailableTime = end_time;
    assembler.vTime[task.station] = start_time;

    unloader.time_start[task.station] = end_time;
    wrlInfo.fullWeldCompleted = true;
}


// 调度下料任务
void Scheduler::scheduleLoadDown(const Task& task) {
    // 确定任务开始时间

    size_t stationIndex = getOneWrlInfoIndex(task.workpieceModel);
    auto &wrlInfo = wrls[stationIndex];

    auto ss = wrlInfo.fullWeldCompleted;
    auto a1 =Robot::Time2Str(unloader.available_time);
    auto a2 =Robot::Time2Str(wrlInfo.nextAvailableTime);
    auto a3 =Robot::Time2Str(loader.available_time);

    std::cout << ( ss ? "true\t":"false\t" ) << a1 << '\t' << a2 << '\t' << a3 << std::endl;
    auto As = wrlInfo.nextAvailableTime + task.duration;
    auto Fs = unloader.time_start[GetFriendSta(task.station)];
    auto Fe = unloader.unloaderTimes[GetFriendSta(task.station)];
    TimeUnit start_time;
    if(As < Fs && As < Fe )
    {
        start_time = wrlInfo.nextAvailableTime;
    }else{
        start_time = std::max(unloader.available_time, wrlInfo.nextAvailableTime);
    }


    auto end_time = start_time + task.duration;

    logger.logTask(task, start_time, end_time);
    logger.logTaskNoThisJoint(task, start_time, end_time,task.link_json);
    for(auto &f:task.link_part_json){
        logger.logTaskPart(task, start_time, end_time,f.second,f.first);
    }


    // 更新卸载机器人的可用时间
    unloader.available_time = end_time;
    // wrlInfo.nextAvailableTime = end_time;

    unloader.unloaderTimes[task.station] = end_time;
    unloader.time_start[task.station] = start_time;
    unloader.unloaderStates[task.station] = true;

    wrlInfo.isWorking = false;
    wrlInfo.fullWeldCompleted = true;
    wrlInfo.currentPart = wrlInfo.totalParts-1;
}

// 获取工位索引
size_t Scheduler::getOneWrlInfoIndex(const std::string& wrlName) {
    for (size_t i = 0; i < wrls.size(); ++i) {
        if (wrls[i].workpieceModel == wrlName) return i;
    }
    return wrls.size(); // 未找到
}



/** 从小严json分类出真实的数据 **/
void OneWrlInfo::CreateWeldJoint(const std::string &json)
{
    std::string writePath = "Plan/runData/" + workpieceModel + "/";
    createDirectories(writePath);
    DMHStruct XYSt = deserializeDMH(GetJsonByPath(json));

    // name = XYSt.StationID == 1 ? "SA":"SB";
    auto mhJ = DMHStruct::MH2Vec(XYSt.mh);
    auto mjn = serializeMJointDataV(mhJ);
    j_full = writePath + "mh.json";
    j_full_DB = writePath + "spotWelding.db";
    fullWeldTime = mjn.size();
    WriteJson(j_full,mjn);

    totalParts = XYSt.dh.size();
    // one.chainID = sch.GetChainByID(one.partID,one.wrlID);


    for(int i = 1;i<totalParts+1;i++){
        PartInfos info;
        info.wrlID = wrlid;
        info.partID = i;

        auto nm = info.GetPartName();

        std::vector<MJointData> XX1;
        nlohmann::json nlj;

        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].assm1);
        nlj = serializeMJointDataV(XX1);
        info.js_Ass1 = writePath+ nm + "_ass1.json";
        WriteJson(info.js_Ass1,nlj);
        info.partAssTimes1 = XX1.size();

        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].dh1);
        nlj = serializeMJointDataV(XX1);
        info.js_t1 = writePath+ nm + "_dh1.json";
        WriteJson(info.js_t1,nlj);
        info.partTimes1 = XX1.size();


        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].assm2);
        nlj = serializeMJointDataV(XX1);
        info.js_Ass2 = writePath+ nm + "_ass2.json";
        WriteJson(info.js_Ass2,nlj);
        info.partAssTimes2 = XX1.size();


        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].dh2);
        nlj = serializeMJointDataV(XX1);
        info.js_t2 = writePath+ nm + "_dh2.json";
        WriteJson(info.js_t2,nlj);
        info.partTimes2 = XX1.size();

        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].part1);
        nlj = serializeMJointDataV(XX1);
        info.js_part1 = writePath+ nm + "_part1.json";
        WriteJson(info.js_part1,nlj);

        XX1 = DMHStruct::OPH2Vec(XYSt.dh[i].part2);
        nlj = serializeMJointDataV(XX1);
        info.js_part2 = writePath+ nm + "_part2.json";
        WriteJson(info.js_part2,nlj);

        parts.push_back(info);

    }


}


// path
void OneWrlInfo::CreateScanJoint(const std::string &json)
{
    std::string writePath = "Plan/runData/" + workpieceModel + "/";
    auto dhs = deserializeMHS(GetJsonByPath(json));
    std::vector<MJointData> XX1 = DMHStruct::MH2Vec(dhs);
    BGSTime = XX1.size();
    if(0 == BGSTime) return;
    auto nlj = serializeMJointDataV(XX1);
    j_scan = writePath + "BGscan.json";
    j_scan_DB = writePath + "plateScan.db";

    WriteJson(j_scan,nlj);
}

void OneWrlInfo::CreateUpJoint(const std::string &json)
{
    std::string writePath = "Plan/runData/" + workpieceModel + "/";
    Uploader upper;
    from_json(GetJsonByPath(json),upper);
    auto dhs = upper.joint;

    std::vector<MJointData> XX1 = DMHStruct::MH2Vec(dhs);
    LoaderTime = XX1.size();
    if(0 == LoaderTime) return;
    auto nlj = serializeMJointDataV(XX1);
    j_up = writePath + "UP.json";
    j_up_DB = writePath + "transport.db";

    WriteJson(j_up,nlj);
    nlj = serializeMJointDataV(DMHStruct::MH2Vec(upper.path));
    j_up_link = writePath + "LinkUp.json";
    WriteJson(j_up_link,nlj);
}

void OneWrlInfo::CreateDownJoint(const std::string &json)
{
    std::string writePath = "Plan/runData/" + workpieceModel + "/";
    createDirectories(writePath + "parts");
    Uploader upper;
    from_json(GetJsonByPath(json),upper);
    auto dhs = upper.joint;
    std::vector<MJointData> XX1 = DMHStruct::MH2Vec(dhs);
    unLoaderTime = XX1.size();
    if(0 == unLoaderTime) return;
    auto nlj = serializeMJointDataV(XX1);
    j_down = writePath + "Down.json";
    j_down_DB = writePath + "transport.db";

    WriteJson(j_down,nlj);

    nlj = serializeMJointDataV(DMHStruct::MH2Vec(upper.path));
    j_down_link = writePath + "LinkDown.json";
    WriteJson(j_down_link,nlj);



    for(auto &k:upper.pathI){
        nlj = serializeMJointDataV(DMHStruct::OPH2Vec(k.second));
        j_down_link_part[k.first] = writePath + "parts/" + std::to_string(k.first) + ".json";
        WriteJson(j_down_link_part[k.first],nlj);
    }

}

std::string PartInfos::GetPartName()
{
    std::string ret;
    ret += 'p';
    ret += std::to_string(partID);
    return ret;
}

Task::Task(TaskType t, const std::string &s, const std::string &wm, float d, JointJsonPath json,
           int w, int p,JointJsonPath lk,JointJsonPath _db)
    : type(t), station(s), workpieceModel(wm), partID(p), duration(d),wrlid(w),link_json(lk),db(_db)
{
    joint_json=((json));
}
